/**
 * @author        Nicolas Bottarini <nicolasbottarini@gmail.com>, 404 <http://www.proyecto404.com>
 * @version       $Rev: 3 $
 * @lastrevision  $Date: 2011-09-12 16:45:37 +0000 (Mon, 12 Sep 2011) $	 
 */
package com.proyecto404.core.util {
	import com.proyecto404.core.BaseObject;
	import com.proyecto404.core.collections.Dictionary;
	import com.proyecto404.core.exception.AbstractMethodException;
	
	import flash.utils.describeType;
	
	/**
	 * @todo Hacer que funcionen los accesors
	 */
	public class Mixin extends BaseObject {
		private var _prototype:*;
		private var _mixinClassName:String;
		private var _mixinNamespace:String;
		
		public function Mixin(prototype:*) {
			_prototype = prototype;
			_mixinClassName = ClassHelper.getClassName(this);
			_mixinNamespace = '__mixin__' + _mixinClassName;
			doInstall();
		}
		
		/**
		 * @abstract
		 */
		public function initialize(obj:*,params:Dictionary):void { throw new AbstractMethodException(); }

		private function doInstall():void {
			// Internal property with installed mixins
			var mixinsVar:String = '__mixins__';
			if (!_prototype.hasOwnProperty(mixinsVar)) {
				_prototype[mixinsVar] = new Array();
				_prototype.setPropertyIsEnumerable(mixinsVar, false);
			}
			
			//Mixin already installed
			if (ArrayHelper.contains(_prototype[mixinsVar], _mixinClassName)) {
				return;
			}

			var info:XML = new XML(describeType(this));
			for each (var method:* in info.elements('method')) {
				var name:String = method.attribute('name');
				var declaredBy:String = method.attribute('declaredBy');
				if (declaredBy != "com.proyecto404.util::Mixin" && !_prototype.hasOwnProperty(name)){ 
					_prototype[name] = this[name];
					_prototype.setPropertyIsEnumerable(name, false);
				}
			}
			
			_prototype[mixinsVar].push(_mixinClassName);
		}
		
		protected function getVariable(obj:*, name:String):Object {
			return obj[_mixinNamespace + name];
		}
		
		protected function setVariable(obj:*, name:String, value:Object):void {
			obj[_mixinNamespace + name] = value;
		}

		public static function install(mixin:Class, obj:*,params:Dictionary = null):void {
			var extendedClass:Class = ClassHelper.getClass(obj);
			var m:Mixin = new mixin(extendedClass.prototype);
			m.initialize(obj, params);
		}
	}
}